#ifdef _WIN32
#include "OliviaPCH.h"
#else
#include "macutils.h"
#endif

#include "OgreFramework.h"

namespace Ogre
{
    template<> OgreFramework* Ogre::Singleton<OgreFramework>::ms_Singleton = 0;
};

OgreFramework::OgreFramework() : m_lua(0), m_inited(false)
{
	m_MoveSpeed			= 0.1f;
	m_RotateSpeed       = 0.3f;
    
	m_bShutDownOgre     = false;
	m_iNumScreenShots   = 0;
    
	m_pRoot				= 0;
	m_pRenderWnd        = 0;
	m_pLog				= 0;
	m_pTimer			= 0;
    
	m_pInputMgr			= 0;
	m_pKeyboard			= 0;
	m_pMouse			= 0;
    
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
    m_ResourcePath = Ogre::macBundlePath() + "/Contents/Resources/";
#elif defined(OGRE_IS_IOS)
    m_ResourcePath = Ogre::macBundlePath() + "/";
#else
    m_ResourcePath = "G:/Olivia/game/";
#endif
    //m_pTrayMgr          = 0;
    m_FrameEvent        = Ogre::FrameEvent();
}

//|||||||||||||||||||||||||||||||||||||||||||||||
#if defined(OGRE_IS_IOS)
bool OgreFramework::initOgre(Ogre::String wndTitle, OIS::KeyListener *pKeyListener, OIS::MultiTouchListener *pMouseListener)
#else
bool OgreFramework::initOgre(Ogre::String wndTitle, OIS::KeyListener *pKeyListener, OIS::MouseListener *pMouseListener)
#endif
{
    if (!InitLuaModule())
    {
        return false;
    }

    new Ogre::LogManager();
	m_pLog = Ogre::LogManager::getSingleton().createLog(m_ResourcePath + "log.log", true, true);
    
	Ogre::String pluginsPath, ogre_cfg_path;
    // only use plugins.cfg if not static
#ifndef OGRE_STATIC_LIB
    pluginsPath = m_ResourcePath + "plugins.cfg";
#endif

#if !defined(OGRE_IS_IOS)
    ogre_cfg_path = m_ResourcePath + "ogre.cfg";
#else
	ogre_cfg_path = Ogre::macBundlePath() + "/ogre.cfg";
#endif

    m_pRoot = new Ogre::Root(pluginsPath, ogre_cfg_path);
    
#ifdef OGRE_STATIC_LIB
    m_StaticPluginLoader.load();
#endif
    
	//setting from ogre.cfg file
	m_pRoot->restoreConfig();
	// setting from dialog
	/*if(!m_pRoot->showConfigDialog())
		return false;*/

    m_pRoot->initialise(false, wndTitle);
    
	// create a render window to get renderer caperbility
	/*m_pRenderWnd = m_pRoot->createRenderWindow(wndTitle, 800, 600, false);
	if (m_pRenderWnd != 0)
	{
		m_pRoot->destroyRenderTarget(m_pRenderWnd);
		m_pRenderWnd = 0;
	}*/

	Ogre::String secName, typeName, archName;
	Ogre::ConfigFile cf;
    cf.load(m_ResourcePath + "resources.cfg");
    
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
    while (seci.hasMoreElements())
    {
        secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
        Ogre::ConfigFile::SettingsMultiMap::iterator i;
        for (i = settings->begin(); i != settings->end(); ++i)
        {
            typeName = i->first;
            archName = i->second;
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || defined(OGRE_IS_IOS)
            // OS X does not set the working directory relative to the app,
            // In order to make things portable on OS X we need to provide
            // the loading with it's own bundle path location
            if (!Ogre::StringUtil::startsWith(archName, "/", false)) // only adjust relative dirs
                archName = Ogre::String(m_ResourcePath + archName);
#endif
            Ogre::ResourceGroupManager::getSingleton().addResourceLocation(m_ResourcePath + archName, typeName, secName);
        }
    }
	//Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
    
	m_pTimer = OGRE_NEW Ogre::Timer();
	m_pTimer->reset();

    m_inited = true;
	if (0 == m_pRenderWnd)
	{
		// do not create window
		return true;
	}
    
	unsigned long hWnd = 0;
    OIS::ParamList paramList;
    m_pRenderWnd->getCustomAttribute("WINDOW", &hWnd);
    
	paramList.insert(OIS::ParamList::value_type("WINDOW", Ogre::StringConverter::toString(hWnd)));
    
	m_pInputMgr = OIS::InputManager::createInputSystem(paramList);
    
#if !defined(OGRE_IS_IOS)
    m_pKeyboard = static_cast<OIS::Keyboard*>(m_pInputMgr->createInputObject(OIS::OISKeyboard, true));
	m_pMouse = static_cast<OIS::Mouse*>(m_pInputMgr->createInputObject(OIS::OISMouse, true));
    
	m_pMouse->getMouseState().height = m_pRenderWnd->getHeight();
	m_pMouse->getMouseState().width	 = m_pRenderWnd->getWidth();
#else
	m_pMouse = static_cast<OIS::MultiTouch*>(m_pInputMgr->createInputObject(OIS::OISMultiTouch, true));
#endif
    
#if !defined(OGRE_IS_IOS)
	if(pKeyListener == 0)
		m_pKeyboard->setEventCallback(this);
	else
		m_pKeyboard->setEventCallback(pKeyListener);
#endif
    
	if(pMouseListener == 0)
		m_pMouse->setEventCallback(this);
	else
		m_pMouse->setEventCallback(pMouseListener);
    
	
	
	/*m_pTrayMgr = new OgreBites::SdkTrayManager("TrayMgr", m_pRenderWnd, m_pMouse, this);
    m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
    m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);
    m_pTrayMgr->hideCursor();*/
    
	m_pRenderWnd->setActive(true);
    
	return true;
}

OgreFramework::~OgreFramework()
{
	if (0 != m_lua) {
        lua_close(m_lua);
    }

    if(m_pInputMgr) OIS::InputManager::destroyInputSystem(m_pInputMgr);
    //if(m_pTrayMgr)  delete m_pTrayMgr;
	if(m_pRoot)     delete m_pRoot;

	if (m_pLog) Ogre::LogManager::getSingleton().destroyLog(m_pLog);
}

bool OgreFramework::keyPressed(const OIS::KeyEvent &keyEventRef)
{
/*#if !defined(OGRE_IS_IOS)
	
	if(m_pKeyboard->isKeyDown(OIS::KC_ESCAPE))
	{
        m_bShutDownOgre = true;
        return true;
	}
    
	if(m_pKeyboard->isKeyDown(OIS::KC_SYSRQ))
	{
		m_pRenderWnd->writeContentsToTimestampedFile("BOF_Screenshot_", ".png");
		return true;
	}
    
	if(m_pKeyboard->isKeyDown(OIS::KC_M))
	{
		static int mode = 0;
		
		if(mode == 2)
		{
			m_pCamera->setPolygonMode(PM_SOLID);
			mode = 0;
		}
		else if(mode == 0)
		{
            m_pCamera->setPolygonMode(PM_WIREFRAME);
            mode = 1;
		}
		else if(mode == 1)
		{
			m_pCamera->setPolygonMode(PM_POINTS);
			mode = 2;
		}
	}
    
	if(m_pKeyboard->isKeyDown(OIS::KC_O))
	{
		if(m_pTrayMgr->isLogoVisible())
        {
            m_pTrayMgr->hideLogo();
            m_pTrayMgr->hideFrameStats();
        }
        else
        {
            m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);
            m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
        }
	}
    
#endif*/
	return true;
}

bool OgreFramework::keyReleased(const OIS::KeyEvent &keyEventRef)
{
	return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

#if defined(OGRE_IS_IOS)
bool OgreFramework::touchMoved(const OIS::MultiTouchEvent &evt)
{
//    OIS::MultiTouchState state = evt.state;
//    int origTransX = 0, origTransY = 0;
//#if !OGRE_NO_VIEWPORT_ORIENTATIONMODE
//    switch(m_pCamera->getViewport()->getOrientationMode())
//    {
//        case Ogre::OR_LANDSCAPELEFT:
//            origTransX = state.X.rel;
//            origTransY = state.Y.rel;
//            state.X.rel = -origTransY;
//            state.Y.rel = origTransX;
//            break;
//            
//        case Ogre::OR_LANDSCAPERIGHT:
//            origTransX = state.X.rel;
//            origTransY = state.Y.rel;
//            state.X.rel = origTransY;
//            state.Y.rel = origTransX;
//            break;
//            
//            // Portrait doesn't need any change
//        case Ogre::OR_PORTRAIT:
//        default:
//            break;
//    }
//#endif
//	m_pCamera->yaw(Degree(state.X.rel * -0.1));
//	m_pCamera->pitch(Degree(state.Y.rel * -0.1));
	
	return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool OgreFramework::touchPressed(const OIS:: MultiTouchEvent &evt)
{
#pragma unused(evt)
	return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool OgreFramework::touchReleased(const OIS:: MultiTouchEvent &evt)
{
#pragma unused(evt)
	return true;
}

bool OgreFramework::touchCancelled(const OIS:: MultiTouchEvent &evt)
{
#pragma unused(evt)
	return true;
}
#else
bool OgreFramework::mouseMoved(const OIS::MouseEvent &evt)
{
	//m_pCamera->yaw(Degree(evt.state.X.rel * -0.1f));
	//m_pCamera->pitch(Degree(evt.state.Y.rel * -0.1f));
	
	return true;
}

bool OgreFramework::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
	return true;
}

bool OgreFramework::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
	return true;
}
#endif

void OgreFramework::updateOgre(double timeSinceLastFrame)
{
	m_MoveScale = m_MoveSpeed   * (float)timeSinceLastFrame;
	m_RotScale  = m_RotateSpeed * (float)timeSinceLastFrame;

#if OGRE_VERSION >= 0x10800
    m_pSceneMgr->setSkyBoxEnabled(true);
#endif
    
	m_TranslateVector = Ogre::Vector3::ZERO;
    
	getInput();
	//moveCamera();
    
	m_FrameEvent.timeSinceLastFrame = timeSinceLastFrame;
    //m_pTrayMgr->frameRenderingQueued(m_FrameEvent);
}

void OgreFramework::getInput()
{
#if !defined(OGRE_IS_IOS)
	if(m_pKeyboard->isKeyDown(OIS::KC_A))
		m_TranslateVector.x = -m_MoveScale;
	
	if(m_pKeyboard->isKeyDown(OIS::KC_D))
		m_TranslateVector.x = m_MoveScale;
	
	if(m_pKeyboard->isKeyDown(OIS::KC_W))
		m_TranslateVector.z = -m_MoveScale;
	
	if(m_pKeyboard->isKeyDown(OIS::KC_S))
		m_TranslateVector.z = m_MoveScale;
#endif
}

bool OgreFramework::InitLuaModule()
{
    if (NULL != m_lua)
    {
        return true;
    }
    
    m_lua = luaL_newstate();
    luaL_openlibs(m_lua);
    if (!lua_ogre::BindOgre(m_lua))
    {
        lua_close(m_lua);
        m_lua = NULL;
        return false;
    }
    if (0 != lua_gettop(m_lua))
    {
        printf("internal error durling register ogre lua module!");
        return false;
    }
    
    return true;
}

static int ScriptPrint (lua_State *L) 
{
	Ogre::Log::Stream stream = Ogre::LogManager::getSingleton().stream();
	stream << "[lua] ";
	int n = lua_gettop(L);  /* number of arguments */
	int i;
	lua_getglobal(L, "tostring");
	for (i=1; i<=n; i++) {
		const char *s;
		lua_pushvalue(L, -1);  /* function to be called */
		lua_pushvalue(L, i);   /* value to print */
		lua_call(L, 1, 1);
		s = lua_tostring(L, -1);  /* get result */
		if (s == NULL)
		  return luaL_error(L, LUA_QL("tostring") " must return a string to "
							   LUA_QL("print"));
		if (i>1) stream << "\t";
		stream << s;
		lua_pop(L, 1);  /* pop result */
	}
	stream << "\n";
	return 0;
}

/*static int AtLuaPanic(lua_State *ls) 
{
	if (lua_gettop(ls) > 1 && lua_isstring(ls, 1))
	{
		PrintTime();
		fputs("[lua] ", stdout);
		fputs(lua_tostring(ls, 1), stdout);
		fputs("\n", stdout);
	}
	return 0;
}*/

static const luaL_reg printlib[] = {
	{"print", ScriptPrint},
	{0, 0}
};

bool OgreFramework::ScriptMain()
{
	lua_getglobal(m_lua, "_G");
	luaL_register(m_lua, 0, printlib);
    
    lua_pushstring(m_lua, "package");
    lua_rawget(m_lua, 1);
    
    lua_pushstring(m_lua, "path");
    lua_rawget(m_lua, -2);
    
    std::string script_path(lua_tostring(m_lua, -1));
    lua_pop(m_lua, 1);
    
    script_path += ";";
    script_path += m_ResourcePath;
    script_path += "?.lua";
    lua_pushstring(m_lua, "path");
    lua_pushstring(m_lua, script_path.c_str());
    lua_rawset(m_lua, -3);
    
	lua_pop(m_lua, 2);

    script_path = m_ResourcePath + "script/main.lua";
    if (lua_ogre::LoadModuleFromFile(m_lua, script_path.c_str(), "main") )
    {
        return lua_ogre::RunVoidFunction(m_lua, "main", "Main");
    }
    else
    {
		m_pLog->stream() << "failed to init script: \n" << lua_tostring(m_lua, -1);
    }
    
    return false;
}

void OgreFramework::scriptUpdate()
{
    if (0 == m_lua)
    {
        return;
    }
    
    lua_ogre::RunVoidFunction(m_lua, "main", "Update");
}